#include "vlan_proce.h"
#include "sys_resource.h"
extern int thread_recv_pcie_signal;
/***
 * 对数据包的处理
 */
void del_pdata(uint8 *rdata, int offset, int vtype, int dlen)
{
    switch (vtype)
    {
    case VLAN_TYPE_0:
    {
        uint32 *ptr = (uint32 *)rdata;
        uint32 parm[3] = {0x01, dlen, 0x00};
        if (sizeof(parm) != offset)
        {
            LOG_ERROR("#ERR: offset is diff size of parm, parm size is : %d \n ");
            return;
        }
        memcpy(ptr, &parm, sizeof(parm));
        return;
    }

    case VLAN_TYPE_1:
        *rdata = 0x00;
        return;

    case VLAN_TYPE_2:
        *rdata = 0x01;
        return;
    case VLAN_TYPE_3:

        return;
    case VLAN_TYPE_4:

        return;
    case VLAN_TYPE_5:

        return;
    default:
        LOG_ERROR("#ERR: error to set vlan buff, vtype: %d \n", vtype);
        return;
    }
}
//获取广播📢 socketId
void SCOKET_UDP_RADI(struct sockaddr_in *client_addr,
                     struct sockaddr_in *local_addr,
                     VlanData *vdata, int local_addr_len)
{
    //网络相关配置
    local_addr->sin_family = AF_INET;
    local_addr->sin_port = htons(vdata->uparm.port);
    local_addr->sin_addr.s_addr = inet_addr(vdata->uparm.sourceIp);

    int udp_data_socket = socket(AF_INET, SOCK_DGRAM, 0);
    if (udp_data_socket < 0)
    {
        LOG_ERROR("#ERR: -[%s:%d]- socket failed ! udp_data_socket: %d \n", vdata->uparm.sourceIp, vdata->uparm.port, udp_data_socket);
        return;
    }
    int ret = bind(udp_data_socket, (struct sockaddr *)local_addr, local_addr_len);

    vdata->udp_data_socket = udp_data_socket;

    if (ret < 0)
    {
        vdata->flag = VD_FLAG_OFF;
        LOG_ERROR("#ERR: -[%s:%d]- err to bind socket, thread_id: %d, err code: %d \n", vdata->uparm.sourceIp, vdata->uparm.port, vdata->thread_id, ret);
        return;
    }
}
//获取组播📢 socketId
void SCOKET_UDP_MULT(struct ip_mreq *mreq, int mreq_len,
                     struct sockaddr_in *client_addr,
                     struct sockaddr_in *local_addr,
                     VlanData *vdata, int local_addr_len)
{

    local_addr->sin_family = AF_INET;
    local_addr->sin_addr.s_addr = htonl(INADDR_ANY);
    local_addr->sin_port = htons(vdata->uparm.port);
    int udp_data_socket = socket(AF_INET, SOCK_DGRAM, 0);

    if (udp_data_socket < 0)
    {
        LOG_ERROR("#ERR: -[%s:%d]- socket failed ! udp_data_socket: %d \n", vdata->uparm.sourceIp, vdata->uparm.port, udp_data_socket);
        return;
    }
    int ret = bind(udp_data_socket, (struct sockaddr *)local_addr, local_addr_len);

    vdata->udp_data_socket = udp_data_socket;

    if (ret < 0)
    {
        vdata->flag = VD_FLAG_OFF;
        LOG_ERROR("#ERR: -[%s:%d]- err to bind socket, thread_id: %d, err code: %d \n", vdata->uparm.sourceIp, vdata->uparm.port, vdata->thread_id, ret);
        return;
    }

    mreq->imr_multiaddr.s_addr = inet_addr(vdata->uparm.sourceIp);
    mreq->imr_interface.s_addr = htonl(INADDR_ANY);
    ret = setsockopt(udp_data_socket, IPPROTO_IP, IP_ADD_MEMBERSHIP, mreq, mreq_len);
    if (ret < 0)
    {
        LOG_ERROR("#ERR: -[%s:%d]- err to set sockopt failed ! ret: %d\n", vdata->uparm.sourceIp, vdata->uparm.port, ret);
        return;
    }
}
void recv_net_data(VlanData *vdata)
{
    char thread_name[20];
    sprintf(thread_name, "%s%d_%d", VLAN_THREAD_NAME, vdata->threadId, vdata->uparm.port);
    prctl(PR_SET_NAME, thread_name);

    // pthread_detach(pthread_self());   //设置分离

    //加入对应的组播
    struct sockaddr_in client_addr = {0};
    struct sockaddr_in local_addr = {0};

    struct ip_mreq mreq; // 多播地址结构体

    memset(&local_addr, 0, sizeof(local_addr));
    int blen = sizeof(local_addr);

    vdata->uparm.type == UDP_MULT
        ? SCOKET_UDP_MULT(&mreq, sizeof(mreq), &client_addr, &local_addr, vdata, blen)
        : SCOKET_UDP_RADI(&client_addr, &local_addr, vdata, blen);

    PackWriteFile *pwf;
    int qlen = 0; //返回的字节数
    int order = 0;
    int offset = vdata->uparm.offset;
    while (1)
    {
        BQueue *queue = mallocBQueue(vdata->qBox);
        memset(queue->rbuf, 0x00, queue->blen);
        if (queue == NULL)
        {
            // LOG_WARN("队列内存已经使用完, VALN 申请不到队列的内存 \n");
            if (!thread_recv_pcie_signal)
            {
                break;
            }
            continue;
        }

        qlen = recvfrom(vdata->udp_data_socket, queue->rbuf + offset, queue->blen - offset, 0, (struct sockaddr *)&client_addr, &blen);
        // LOG_DEBUG("数据源： %d %s:%d %p\n",vdata->udp_data_socket, vdata->sourceIp, vdata->prot);
        if (!thread_recv_pcie_signal)
        {
            vdata->istop = ISTOP_YES;
            break;
        }

        // int i;
        // printf("%d ---> len: %d\n", vdata->uparm.vtype, qlen);
        // for (i = 0; i < qlen + 1; i++) {
        // 	printf("%x ", ptr[i]);
        // }
        //对数据包进行额外的处理
        del_pdata((uint8 *)queue->rbuf, offset, vdata->uparm.vtype, qlen);
        queue->qlen = qlen + offset;
        queue->channel = vdata->channel;
        queue->type = QU_VALN;

        order = GET_WRITE_THREAD_INDEX(vdata->channel);
        pwf = vdata->pwf + order;

#ifdef QUEUE_STATUS
        LOG_INFO("qlen: %d, queue: %p, pwf: %p, order: %d, FREE: %d, channel: %d \n",
                 qlen, queue, pwf, order,
                 (PCIE_QUEUE_NUM - getBusyNumBQueue(vdata->qBox->bQueue)), queue->channel);
#endif

        if (KT_OK != inputOrderQueueEle(pwf->oqBox, queue))
        {
            LOG_ERROR("VALN 队列 %p 已满, pwf: %p, VALN_ID: %d, VALN_PORT: %d \n", pwf->oqBox, pwf, vdata->threadId, vdata->uparm.port);
        }
    }
}

int getVlanBusyData(VlanData *vdata, int num)
{
    int count = 0, i = 0;
    while ((i++) < num)
    {
        if (vdata->istop == ISTOP_YES)
        {
            count++;
        }
        *vdata++;
    }
    return count;
}

/***
 * 初始化网络参数
 */
void init_vdata(VlanData *vdata, PackWriteFile *pwf)
{
    size_t i = 0;
    RecvCmd *recv_cmd = pwf->recv_cmd;

    UdpParam pdata[VALN_NUM] = {
        {recv_cmd->SourceData_gengzongmubiao, "224.9.200.2", 4369, UDP_MULT, VLAN_TYPE_0, 12},              //跟踪目标二次信息      头字节 12 字节, 「0x01, dlen, 0x00」
        {recv_cmd->SourceData_kongzhixinxi, "224.9.200.3", 2000, UDP_MULT, VLAN_TYPE_1, 1},                 //控制信息和状态信息    头 1字节加 0
        {recv_cmd->SourceData_kongzhixinxi, "224.9.200.5", 4660, UDP_MULT, VLAN_TYPE_2, 1},                 //控制信息和状态信息    头 1字节加 1
        {recv_cmd->SourceData_waibuyindao, "224.9.200.2", 4370, UDP_MULT, VLAN_TYPE_3, 0},                  //外部引导数据
        {recv_cmd->SourceData_mubiaoshibie, "224.9.200.3", 2003, UDP_RADI, VLAN_TYPE_4, 0},                 //目标识别特征数据库
        {recv_cmd->SourceData_ganraozhencha_w, "192.168.137.12", 7216, UDP_RADI, VLAN_TYPE_5, 0}};          //干扰侦察数据          

    for (i = 0; i < VALN_NUM; i++)
    {
        UdpParam *param = &pdata[i];
        vdata->threadId = i;
        vdata->flag = param->flag;                      //0 关闭的,  1 开启
        vdata->qBox = pwf->qBox;
        memcpy(&vdata->uparm, param, sizeof(UdpParam));
        vdata->channel = PCIE_OPTI_NUM + i;
        vdata->pwf = pwf;
        if (vdata->flag != VD_FLAG_OFF)
        {
            pthread_create(&vdata->thread_id, NULL, recv_net_data, (void *)vdata);
        }
        *vdata++;
    }
}
/**
 * 检查网络并上报状态
 */
void check_status_vdata(VlanData *vdata, PackWriteFile *pwf)
{
    size_t i = 0;
    int times = 1000; //间隔时间 4000ms
    PackWriteFile *cpwf = NULL;
    uint64 pre_record[VALN_NUM] = {0};
    VlanInfoEth vie = {0};
    vie.head = ETH_HEAD;
    vie.type = ETH_TYPE_VLANG;
    vie.tail = sizeof(VlanInfoEth);
    uint64 dif_len;
    while (1)
    {
        /** 检测网络状态信息并上报 */
        for (i = 0; i < VALN_NUM; i++)
        {
            if (vdata[i].flag == VD_FLAG_OFF)
            {
                vie.vsd[i].speed = 0;
                vie.vsd[i].status = VSTATUS_AWAIT;
            }
            else
            {
                FilePro *cfile = GET_PWF_FILE_INDEX(pwf, vdata[i].channel);
                dif_len = cfile->fsize - pre_record[i];
                pre_record[i] = cfile->fsize;
                vie.vsd[i].speed = FLOAT_ACCURACY(FLOAT_ACCURACY(dif_len, SIZE_MB), times / 1000.0);
                vie.vsd[i].status = VSTATUS_OK;
            }
            // LOG_DEBUG("i: %d, dif_len: %d, speed: %lf, status: %d \n", i, dif_len, vie.vsd[i].speed, vie.vsd[i].status);
        }
        // LOG_DEBUG(" \n");

       

        if (!thread_recv_pcie_signal)
        {
            /** 强制执行结束阻塞线程 */
            for (i = 0; i < VALN_NUM; i++)
            {
                if (vdata[i].flag == VD_FLAG_ON)
                {
                    shutdown(vdata[i].udp_data_socket, SHUT_RDWR);
                    close(vdata[i].udp_data_socket);
                }
            }
            //发送网络数据包，状态设置未待机状态
            for( i = 0; i < VALN_NUM; i++) {
                vie.vsd[i].speed = 0;
                vie.vsd[i].status = VSTATUS_AWAIT;
            }
            sendToMsg(&vie,INFO_VLAN);
            break;
        }
         //#note: 上报网络状态
        sendToMsg(&vie, INFO_VLAN);
        
        usleep(times * 1000); //十毫秒
    }
}
